package sg.edu.ntu.metaweb.http;

import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.util.Date;
import java.util.HashMap;

import sg.edu.ntu.metaweb.pastry.PastryNodeHandle;


public class RequestHandler extends Thread {
	
	private int requestID;
	
	private Socket socket;
	private BufferedReader in;
	private BufferedOutputStream out;
	

	private PastryNodeHandle pastryNodeHandle;
	
    public RequestHandler(Socket socket, PastryNodeHandle pastryNodeHandler) throws IOException {
    	
    	this.requestID = (new Date()).hashCode();
    	
    	this.socket = socket;
    	this.socket.setSoTimeout(30000);
    	in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        out = new BufferedOutputStream(socket.getOutputStream());
        
        this.pastryNodeHandle = pastryNodeHandler;
	}
	
    public int getRequestID() {
		return requestID;
	}

	private static void sendHeader(BufferedOutputStream out, int code, String contentType, long contentLength, long lastModified) throws IOException {
        out.write(("HTTP/1.0 " + code + " OK\r\n" + 
                   "Date: " + new Date().toString() + "\r\n" +
                   "Server: JibbleWebServer/1.0\r\n" +
                   "Content-Type: " + contentType + "\r\n" +
                   "Expires: Thu, 01 Dec 1994 16:00:00 GMT\r\n" +
                   ((contentLength != -1) ? "Content-Length: " + contentLength + "\r\n" : "") +
                   "Last-modified: " + new Date(lastModified).toString() + "\r\n" +
                   "\r\n").getBytes());
    }
    
    private static void sendError(BufferedOutputStream out, int code, String message) throws IOException {
        message = message + "<hr>";
        sendHeader(out, code, "text/html", message.length(), System.currentTimeMillis());
        out.write(message.getBytes());
        out.flush();
        out.close();
    }
    
    
    public void run() {
        System.out.println("Handle new request:");
		try {
			String request = in.readLine();
			if (request == null || !request.startsWith("GET ") || !(request.endsWith(" HTTP/1.0") || request.endsWith("HTTP/1.1"))) {
                // Invalid request type (no "GET")
                sendError(out, 500, "Invalid Method.");
                return;
            }    
			String queryString = request.substring(6, request.length() - 9);
			pastryNodeHandle.httpConnectionManager.popRequestHandler(this);
			pastryNodeHandle.handleRequest(this, getQueryMap(queryString));
			
			synchronized (this) {
				wait(); 
			} 
			
		} catch(IOException ioe) {
		    ioe.printStackTrace();
		} catch(InterruptedException ioe) {
		    ioe.printStackTrace();
		}
		finally {
		    try {
		    	in.close();
		    	out.close();
		    	socket.close();
		    	System.out.println("[RequestHandler] streams and socket closed.");
		    } 
		    catch(IOException ioe) {
		    	ioe.printStackTrace();
		    }
		}
    }
    
    public static HashMap<String, String> getQueryMap(String query)  
    {  
        String[] params = query.split("&");  
        HashMap<String, String> map = new HashMap<String, String>();  
        for (String param : params)  
        {  
            String name = param.split("=")[0];  
            String value = param.split("=")[1];  
            map.put(name, value);  
        }  
        return map;  
    }
    
    
    public void write(String output) {
   		try {
   			System.out.println(output);
   			this.sendHeader(out, 200, "text/xml", -1, System.currentTimeMillis());
   			this.out.write((output).getBytes());
   			this.out.flush();   			
   		}
   		catch (IOException exc) {
   			exc.printStackTrace();
   		}
   		finally {
   			synchronized (this) { 
   				this.notify(); 
   			}  
   		}
    }
}

